package com.bincloud.vue.admin.web.service.ums.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bincloud.vue.admin.common.enums.FlagEnum;
import com.bincloud.vue.admin.common.enums.ums.UmsUserGenderEnum;
import com.bincloud.vue.admin.common.enums.ums.UmsUserStateEnum;
import com.bincloud.vue.admin.common.exception.BaseException;
import com.bincloud.vue.admin.common.exception.CodeMsg;
import com.bincloud.vue.admin.common.model.dto.response.BasePageResDTO;
import com.bincloud.vue.admin.common.util.BaseEntityUtils;
import com.bincloud.vue.admin.common.util.ObjectUtils;
import com.bincloud.vue.admin.common.util.StringUtils;
import com.bincloud.vue.admin.common.util.ValidateUtils;
import com.bincloud.vue.admin.dao.mapper.ums.UmsUserMapper;
import com.bincloud.vue.admin.model.entity.UmsUser;
import com.bincloud.vue.admin.web.dto.ums.user.UmsUserPageReqDTO;
import com.bincloud.vue.admin.web.dto.ums.user.UmsUserPageResDTO;
import com.bincloud.vue.admin.web.dto.ums.user.UmsUserReqDTO;
import com.bincloud.vue.admin.web.dto.ums.user.UmsUserSaveReqDTO;
import com.bincloud.vue.admin.web.service.ums.IUmsUserService;
import com.bincloud.vue.admin.web.util.config.UmsUserConfig;
import com.bincloud.vue.admin.web.util.request.RequestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author bincloud, mvpzhou
 * @since 2022-02-16
 */
@Service
@Slf4j
public class UmsUserServiceImpl extends ServiceImpl<UmsUserMapper, UmsUser> implements IUmsUserService {

    @Resource
    private UmsUserConfig userConfig;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private RequestService requestService;

    /**
     * 用户分页查询
     *
     * @param reqDTO 入参
     * @return 返参
     */
    @Override
    public BasePageResDTO<List<UmsUserPageResDTO>> pageUser(UmsUserPageReqDTO reqDTO) {
        // 分页查询入参
        QueryWrapper<UmsUser> queryWrapper = new QueryWrapper<>();
        BeanUtils.copyProperties(reqDTO, queryWrapper);
        Page<UmsUser> queryPage = new Page<>(reqDTO.getPageNo(), reqDTO.getPageSize());
        Page<UmsUser> resPage = this.page(queryPage, queryWrapper);
        // 组装参数
        List<UmsUserPageResDTO> resList = resPage.getRecords().stream().map(source -> {
            UmsUserPageResDTO target = new UmsUserPageResDTO();
            // 忽略密码
            BeanUtils.copyProperties(source, target, "password");
            return target;
        }).collect(Collectors.toList());
        // 组装返参
        BasePageResDTO<List<UmsUserPageResDTO>> resDTO = new BasePageResDTO<>();
        resDTO.setPageNo(resPage.getCurrent());
        resDTO.setPageSize(resPage.getSize());
        resDTO.setTotalPage(resPage.getPages());
        resDTO.setTotal(resPage.getTotal());
        resDTO.setContent(resList);
        return resDTO;
    }

    /**
     * 用户新增
     *
     * @param reqDTO 入参
     * @return 返参
     */
    @Override
    public boolean saveUser(UmsUserSaveReqDTO reqDTO) {
        // 验证入参
        this.validateUmsUserSaveReqDTO(reqDTO);
        // 当前时间
        LocalDateTime now = LocalDateTime.now();
        // 组装用户实体
        UmsUser user = new UmsUser();
        BeanUtils.copyProperties(reqDTO, user);
        user.setLastLogin(now);
        user.setAccountExpire(now.plusDays(userConfig.getAccountExpire()));
        user.setCredentialsExpire(now.plusDays(userConfig.getCredentialsExpire()));
        user.setState(reqDTO.getState());
        user.setFlag(FlagEnum.UNDELETED.getCode());
        BaseEntityUtils.create(user, requestService.getUsername());
        // 保存数据
        return this.save(user);
    }

    /**
     * 用户锁定
     *
     * @param reqDTO 入参
     * @return 返参
     */
    @Override
    public boolean lockUser(UmsUserReqDTO reqDTO) {
        UmsUser user = this.getUser(reqDTO.getUsername());
        if (ObjectUtils.isEmpty((user))) {
            throw new BaseException(CodeMsg.UMS_USER_NOT_EXIST);
        }
        if (!ObjectUtils.equals(UmsUserStateEnum.LOCKOUT.getCode(), user.getState())) {
            throw new BaseException(CodeMsg.UMS_USER_STATE_ERROR);
        }
        user.setState(UmsUserStateEnum.LOCKOUT.getCode());
        BaseEntityUtils.modify(user, requestService.getUsername());
        // 更新数据
        return this.updateById(user);
    }

    /**
     * 用户解除锁定
     *
     * @param reqDTO 入参
     * @return 返参
     */
    @Override
    public boolean unlockUser(UmsUserReqDTO reqDTO) {
        UmsUser user = this.getUser(reqDTO.getUsername());
        if (ObjectUtils.isEmpty((user))) {
            throw new BaseException(CodeMsg.UMS_USER_NOT_EXIST);
        }
        if (ObjectUtils.equals(UmsUserStateEnum.LOCKOUT.getCode(), user.getState())) {
            throw new BaseException(CodeMsg.UMS_USER_STATE_ERROR);
        }
        user.setState(UmsUserStateEnum.AVAILABLE.getCode());
        BaseEntityUtils.modify(user, requestService.getUsername());
        // 更新数据
        return this.updateById(user);
    }

    /**
     * 用户删除
     *
     * @param reqDTO 入参
     * @return 返参
     */
    @Override
    public boolean removeUser(UmsUserReqDTO reqDTO) {
        UmsUser user = this.getUser(reqDTO.getUsername());
        if (ObjectUtils.isEmpty((user))) {
            throw new BaseException(CodeMsg.UMS_USER_NOT_EXIST);
        }
        user.setFlag(FlagEnum.DELETED.getCode());
        BaseEntityUtils.modify(user, requestService.getUsername());
        // 更新数据
        return this.updateById(user);
    }

    /**
     * 用户重置
     *
     * @param reqDTO 入参
     * @return 返参
     */
    @Override
    public boolean resetUser(UmsUserReqDTO reqDTO) {
        UmsUser user = this.getUser(reqDTO.getUsername());
        if (ObjectUtils.isEmpty((user))) {
            throw new BaseException(CodeMsg.UMS_USER_NOT_EXIST);
        }
        if (!ObjectUtils.equals(UmsUserStateEnum.LOCKOUT.getCode(), user.getState())) {
            throw new BaseException(CodeMsg.UMS_USER_STATE_ERROR);
        }
        LocalDateTime now = LocalDateTime.now();
        user.setPassword(encryptPassword(userConfig.getPasswordDefault()));
        user.setAccountExpire(now.plusDays(userConfig.getAccountExpire()));
        user.setCredentialsExpire(now.plusDays(userConfig.getCredentialsExpire()));
        user.setState(UmsUserStateEnum.TO_BE_ACTIVATED.getCode());
        user.setFlag(FlagEnum.UNDELETED.getCode());
        BaseEntityUtils.modify(user, requestService.getUsername());
        // 更新数据
        return this.updateById(user);
    }

    /**
     * 获取用户信息
     *
     * @param username 入参 用户名
     * @return 用户信息
     */
    @Override
    public UmsUser getUser(String username) {
        return this.getOne(Wrappers.<UmsUser>lambdaQuery().eq(UmsUser::getUsername, username));
    }

    /**
     * 更新用户最新登录时间
     *
     * @param username 入参 用户名
     */
    @Override
    public void updateLastLogin(String username) {
        this.update(Wrappers.<UmsUser>lambdaUpdate().set(UmsUser::getLastLogin, LocalDateTime.now()).eq(UmsUser::getUsername, username));
    }

    // save
    private void validateUmsUserSaveReqDTO(UmsUserSaveReqDTO reqDTO) {
        // 用户重复添加
        this.validateUserExisted(reqDTO.getUsername());

        // 用户
        this.validateAccount(reqDTO.getUsername());

        // 密码
        if (StringUtils.isBlank(reqDTO.getPassword())) {
            // 默认密码
            reqDTO.setPassword(userConfig.getPasswordDefault());
        }
        this.validatePassword(reqDTO.getPassword());
        reqDTO.setPassword(encryptPassword(reqDTO.getPassword()));

        // 性别
        this.validateGender(reqDTO.getGender());

        // 头像
        if (StringUtils.isBlank(reqDTO.getAvatar())) {
            reqDTO.setAvatar(userConfig.getAvatar());
        }
        this.validateAvatar(reqDTO.getAvatar());

        // 昵称
        if (StringUtils.isBlank(reqDTO.getNickname())) {
            reqDTO.setNickname(reqDTO.getUsername());
        }
        validateNickname(reqDTO.getNickname());

        // 邮箱
        this.validateEmail(reqDTO.getEmail());

        // 账号有效期
        LocalDateTime now = LocalDateTime.now();
        if (ObjectUtils.isEmpty(reqDTO.getAccountExpire())) {
            reqDTO.setAccountExpire(now.plusDays(userConfig.getAccountExpire()));
        }
        this.validateAccountExpire(reqDTO.getAccountExpire());

        // 密码有效期
        if (ObjectUtils.isEmpty(reqDTO.getCredentialsExpire())) {
            reqDTO.setCredentialsExpire(now.plusDays(userConfig.getCredentialsExpire()));
        }
        this.validateCredentialsExpire(reqDTO.getCredentialsExpire());

        // 状态
        this.validateState(reqDTO.getState());
    }

    private void validateUserExisted(String username) {
        UmsUser user = this.getUser(username);
        if (ObjectUtils.isNotNull((user))) {
            throw new BaseException(CodeMsg.UMS_USER_EXISTED);
        }
    }

    private void validateState(Integer state) {
        if (ObjectUtils.isEmpty(state) || UmsUserStateEnum.noCode(state)) {
            throw new BaseException(CodeMsg.UMS_USER_STATE_ERROR);
        }
    }

    private void validateCredentialsExpire(LocalDateTime ldt) {
        if (ObjectUtils.isEmpty(ldt) || ldt.isBefore(LocalDateTime.now())) {
            throw new BaseException(CodeMsg.UMS_USER_CREDENTIALS_EXPIRE);
        }
    }

    private void validateAccountExpire(LocalDateTime ldt) {
        if (ObjectUtils.isEmpty(ldt) || ldt.isBefore(LocalDateTime.now())) {
            throw new BaseException(CodeMsg.UMS_USER_ACCOUNT_EXPIRE);
        }
    }

    private void validateEmail(String email) {
        if (StringUtils.isBlank(email) && !ValidateUtils.isEmail(email)) {
            throw new BaseException(CodeMsg.UMS_USER_EMAIL_ERROR);
        }
    }

    private void validateNickname(String nickname) {
        if (StringUtils.isBlank(nickname) || !ValidateUtils.isChinese(nickname) || !ValidateUtils.isEnglish(nickname)) {
            throw new BaseException(CodeMsg.UMS_USER_NICKNAME_ERROR);
        }
    }

    @SuppressWarnings("all")
    private void validateAvatar(String avatar) {
        if (StringUtils.isBlank(avatar) || !validateAvatarFileId(avatar)){
            throw new BaseException(CodeMsg.UMS_USER_AVATAR_ERROR);
        }
    }

    @SuppressWarnings("all")
    private boolean validateAvatarFileId(String avatar) {
        // TODO 判断头像 fileId 是否存在
        return true;
    }

    private void validateGender(Integer gender) {
        if (ObjectUtils.isEmpty(gender) || !UmsUserGenderEnum.hasCode(gender)) {
            throw new BaseException(CodeMsg.UMS_USER_GENDER_ERROR);
        }
    }

    private void validatePassword(String password) {
        if (StringUtils.isBlank(password) || !ValidateUtils.isPassword(password, userConfig.getPasswordValidateType())) {
            throw new BaseException(CodeMsg.UMS_USER_PASSWORD_ERROR);
        }
    }

    private void validateAccount(String username) {
        if (StringUtils.isBlank(username) || !ValidateUtils.isAccount(username)) {
            throw new BaseException(CodeMsg.UMS_USER_ACCOUNT_ERROR);
        }
    }

    public String encryptPassword(String password) {
        return passwordEncoder.encode(password);
    }


}
